package com.chensf.studydemo.common

import android.Manifest
import android.annotation.SuppressLint
import android.graphics.Color
import android.os.Bundle
import android.os.Environment
import android.os.SystemClock
import android.util.DisplayMetrics
import android.util.Log
import android.util.Size
import android.view.ViewGroup
import android.view.WindowManager
import android.widget.Toast
import androidx.activity.result.contract.ActivityResultContracts
import androidx.annotation.NonNull
import androidx.annotation.Nullable
import androidx.appcompat.app.AppCompatActivity
import androidx.camera.core.*
import androidx.camera.core.VideoCapture.OnVideoSavedCallback
import androidx.camera.extensions.*
import androidx.camera.lifecycle.ProcessCameraProvider
import androidx.core.content.ContextCompat
import com.chensf.studydemo.BarUtils
import com.chensf.studydemo.R
import com.google.common.util.concurrent.ListenableFuture
import kotlinx.android.synthetic.main.activity_camerax_demo.*
import java.io.File
import java.util.concurrent.ExecutionException
import java.util.concurrent.ExecutorService
import java.util.concurrent.Executors


class CameraXDemo : AppCompatActivity() {
    private var outputFilePath: String = ""
    private val TAG = "CameraX"
    private var mCamera: Camera? = null
    private lateinit var mImageAnalysis: ImageAnalysis
    private lateinit var mVideoCapture: VideoCapture
    private lateinit var mImageCapture: ImageCapture
    private lateinit var mPreview: Preview
    private var mLensFacing: Int = CameraSelector.LENS_FACING_BACK
    private lateinit var executorService: ExecutorService
    private var mCameraProvider: ProcessCameraProvider? = null
    private val RATIO_4_3_VALUE = 4.0 / 3.0
    private val RATIO_16_9_VALUE = 16.0 / 9.0
    private var isRecording = false


    @SuppressLint("RestrictedApi")
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON or WindowManager.LayoutParams.FLAG_FULLSCREEN) // 防止锁屏
        BarUtils.setStatusBarColor(this, Color.TRANSPARENT)
        BarUtils.setStatusBarLightMode(this, true)
        setContentView(R.layout.activity_camerax_demo)
        executorService = Executors.newSingleThreadExecutor()
        val permissions = arrayOf(
            Manifest.permission.WRITE_EXTERNAL_STORAGE,
            Manifest.permission.READ_EXTERNAL_STORAGE,
            Manifest.permission.CAMERA,
            Manifest.permission.RECORD_AUDIO
        )
        registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) {
            setUpCamera()
        }.launch(permissions)
        updateCameraUi()

        recordBtn.setOnClickListener {
            if(isRecording){
                isRecording = false
                recordBtn.setBackgroundResource(R.drawable.shipin_icon_kaishipaishe_default)
                mVideoCapture.stopRecording()
                chronometer.stop()
                chronometer.base = SystemClock.elapsedRealtime()
            }else{
                isRecording = true
                recordBtn.setBackgroundResource(R.drawable.shipin_icon_zanting_default)
                startRecord()
                chronometer.base = SystemClock.elapsedRealtime()
                chronometer.format = "%s"
                chronometer.start()
            }
        }


        switchCamera.setOnClickListener {
            if (CameraSelector.LENS_FACING_FRONT == mLensFacing){
                mLensFacing = CameraSelector.LENS_FACING_BACK;
            }else {
                mLensFacing = CameraSelector.LENS_FACING_FRONT;
            }
            bindCameraUseCases();
        }
    }

    @SuppressLint("RestrictedApi")
    private fun startRecord() {
        //创建视频保存的文件地址

        //创建视频保存的文件地址
        val file = File(
            getExternalFilesDir(Environment.DIRECTORY_PICTURES)!!.absolutePath,
            System.currentTimeMillis().toString() + ".mp4"
        )
        val metadata = VideoCapture.Metadata()
        val outputFileOptions: VideoCapture.OutputFileOptions =
            VideoCapture.OutputFileOptions.Builder(file).build()
        mVideoCapture.startRecording(
            outputFileOptions,
            Executors.newSingleThreadExecutor(),
            object : OnVideoSavedCallback {
                override fun onVideoSaved(@NonNull outputFileResults: VideoCapture.OutputFileResults) {
                    outputFilePath = file.getAbsolutePath()
                    Log.e(TAG, "onVideoSaved: $outputFilePath")
                }

                override fun onError(
                    videoCaptureError: Int,
                    @NonNull message: String,
                    @Nullable cause: Throwable?
                ) {
                    cause?.printStackTrace()
                    Log.e(TAG, "onError:录制出错-$message")
                }
            })
    }

    private fun updateCameraUi() {
        //必须先remove在add这样视频流画面才能正确的显示出来
        val parent = preview.getParent() as ViewGroup
        parent.removeView(preview)
        parent.addView(preview, 0)
    }

    private fun setUpCamera() {

        //Future表示一个异步的任务，ListenableFuture可以监听这个任务，当任务完成的时候执行回调
        val cameraProviderFuture: ListenableFuture<ProcessCameraProvider> =
            ProcessCameraProvider.getInstance(this)
        cameraProviderFuture.addListener(Runnable {
            try {
                mCameraProvider = cameraProviderFuture.get()
                //选择摄像头的朝向
                mLensFacing = getLensFacing()
                if (mLensFacing === -1) {
                    Toast.makeText(
                        applicationContext,
                        "无可用的设备cameraId!,请检查设备的相机是否被占用",
                        Toast.LENGTH_SHORT
                    ).show()
                    return@Runnable
                }
                // 构建并绑定照相机用例
                bindCameraUseCases()
            } catch (e: ExecutionException) {
                e.printStackTrace()
            } catch (e: InterruptedException) {
                e.printStackTrace()
            }
        }, ContextCompat.getMainExecutor(this))
    }

    @SuppressLint("RestrictedApi")
    private fun bindCameraUseCases() {
        //获取屏幕的分辨率
        val displayMetrics = DisplayMetrics()
        preview.getDisplay().getRealMetrics(displayMetrics)
        //获取宽高比
        val screenAspectRatio: Int =
            aspectRatio(displayMetrics.widthPixels, displayMetrics.heightPixels)
        val rotation: Int = preview.getDisplay().getRotation()
        if (mCameraProvider == null) {
            Toast.makeText(applicationContext, "相机初始化失败", Toast.LENGTH_SHORT).show()
            return
        }
        val cameraProvider = mCameraProvider
        val cameraSelector = CameraSelector.Builder().requireLensFacing(mLensFacing).build()
        val pBuilder = Preview.Builder()
        setPreviewExtender(pBuilder, cameraSelector)
        mPreview = pBuilder //设置宽高比
//            .setTargetAspectRatio(screenAspectRatio) //设置当前屏幕的旋转
            .setTargetResolution(Size(1080,1920))
            .setTargetRotation(rotation)
            .build()
        val builder = ImageCapture.Builder()
        setImageCaptureExtender(builder, cameraSelector)
        mImageCapture = builder //优化捕获速度，可能降低图片质量
            .setCaptureMode(ImageCapture.CAPTURE_MODE_MINIMIZE_LATENCY) //设置宽高比
//            .setTargetAspectRatio(screenAspectRatio) //设置初始的旋转角度
            .setTargetRotation(rotation)
            .setTargetResolution(Size(540,960))
            .build()
        mVideoCapture = VideoCapture.Builder() //设置当前旋转
            .setTargetRotation(rotation) //设置宽高比
//            .setTargetAspectRatio(screenAspectRatio) //                分辨率
            .setTargetResolution(Size(1080,1920))
            //视频帧率  越高视频体积越大
            .setVideoFrameRate(24) //bit率  越大视频体积越大
            .setBitRate((1.5f*1024 * 1024).toInt())
            .build()
        mImageAnalysis = ImageAnalysis.Builder()
            .setTargetAspectRatio(screenAspectRatio)
            .setTargetRotation(rotation)
            .build()
        mImageAnalysis.setAnalyzer(executorService, ImageAnalysis.Analyzer { })


        //重新绑定之前必须先取消绑定
        cameraProvider?.unbindAll()
        mCamera = cameraProvider?.bindToLifecycle(
            this,
            cameraSelector, mPreview, mImageCapture, mVideoCapture
        )
        mPreview.setSurfaceProvider(preview.surfaceProvider)
    }

    private fun aspectRatio(widthPixels: Int, heightPixels: Int): Int {
        val previewRatio =
            Math.max(widthPixels, heightPixels).toDouble() / Math.min(widthPixels, heightPixels)
                .toDouble()
        return if (Math.abs(previewRatio - RATIO_4_3_VALUE) <= Math.abs(previewRatio - RATIO_16_9_VALUE)) {
            AspectRatio.RATIO_4_3
        } else AspectRatio.RATIO_16_9
    }

    private fun getLensFacing(): Int {
        if (hasBackCamera()) {
            return CameraSelector.LENS_FACING_BACK
        }
        return if (hasFrontCamera()) {
            CameraSelector.LENS_FACING_FRONT
        } else -1
    }

    /**
     * 是否有后摄像头
     */
    private fun hasBackCamera(): Boolean {
        if (mCameraProvider == null) {
            return false
        }
        try {
            return mCameraProvider!!.hasCamera(CameraSelector.DEFAULT_BACK_CAMERA)
        } catch (e: CameraInfoUnavailableException) {
            e.printStackTrace()
        }
        return false
    }

    /**
     * 是否有前摄像头
     */
    private fun hasFrontCamera(): Boolean {
        if (mCameraProvider == null) {
            return false
        }
        try {
            return mCameraProvider!!.hasCamera(CameraSelector.DEFAULT_BACK_CAMERA)
        } catch (e: CameraInfoUnavailableException) {
            e.printStackTrace()
        }
        return false
    }

    /**
     * 给拍照设置外部预览
     * @param builder
     * @param cameraSelector
     */
    private fun setImageCaptureExtender(
        builder: ImageCapture.Builder,
        cameraSelector: CameraSelector
    ) {
        val autoImageCaptureExtender = AutoImageCaptureExtender.create(builder)
        if (autoImageCaptureExtender.isExtensionAvailable(cameraSelector)) {
            autoImageCaptureExtender.enableExtension(cameraSelector)
        }
        val bokehImageCaptureExtender = BokehImageCaptureExtender.create(builder)
        if (bokehImageCaptureExtender.isExtensionAvailable(cameraSelector)) {
            bokehImageCaptureExtender.enableExtension(cameraSelector)
        }
        val hdrImageCaptureExtender = HdrImageCaptureExtender.create(builder)
        if (hdrImageCaptureExtender.isExtensionAvailable(cameraSelector)) {
            hdrImageCaptureExtender.enableExtension(cameraSelector)
        }
        val beautyImageCaptureExtender = BeautyImageCaptureExtender.create(builder)
        if (beautyImageCaptureExtender.isExtensionAvailable(cameraSelector)) {
            beautyImageCaptureExtender.enableExtension(cameraSelector)
        }
        val nightImageCaptureExtender = NightImageCaptureExtender.create(builder)
        if (nightImageCaptureExtender.isExtensionAvailable(cameraSelector)) {
            nightImageCaptureExtender.enableExtension(cameraSelector)
        }
    }

    /**
     * 给预览设置外部扩展
     * @param builder
     * @param cameraSelector
     */
    private fun setPreviewExtender(builder: Preview.Builder, cameraSelector: CameraSelector) {
        val extender = AutoPreviewExtender.create(builder)
        if (extender.isExtensionAvailable(cameraSelector)) {
            extender.enableExtension(cameraSelector)
        }
        val bokehPreviewExtender = BokehPreviewExtender.create(builder)
        if (bokehPreviewExtender.isExtensionAvailable(cameraSelector)) {
            bokehPreviewExtender.enableExtension(cameraSelector)
        }
        val hdrPreviewExtender = HdrPreviewExtender.create(builder)
        if (hdrPreviewExtender.isExtensionAvailable(cameraSelector)) {
            hdrPreviewExtender.enableExtension(cameraSelector)
        }
        val beautyPreviewExtender = BeautyPreviewExtender.create(builder)
        if (beautyPreviewExtender.isExtensionAvailable(cameraSelector)) {
            beautyPreviewExtender.enableExtension(cameraSelector)
        }
        val nightPreviewExtender = NightPreviewExtender.create(builder)
        if (nightPreviewExtender.isExtensionAvailable(cameraSelector)) {
            nightPreviewExtender.enableExtension(cameraSelector)
        }
    }

    override fun onDestroy() {
        executorService.shutdown()
        super.onDestroy()
    }
}